#include "shadercodetext.h"

const int mirrorbytes[256] = {
    0 ,128 ,64 ,192 ,32 ,160 ,96 ,224 ,16 ,144 ,80 ,208 ,48 ,176 ,112 ,240 ,
    8 ,136 ,72 ,200 ,40 ,168 ,104 ,232 ,24 ,152 ,88 ,216 ,56 ,184 ,120 ,248 ,
    4 ,132 ,68 ,196 ,36 ,164 ,100 ,228 ,20 ,148 ,84 ,212 ,52 ,180 ,116 ,244 ,
    12 ,140 ,76 ,204 ,44 ,172 ,108 ,236 ,28 ,156 ,92 ,220 ,60 ,188 ,124 ,252 ,
    2 ,130 ,66 ,194 ,34 ,162 ,98 ,226 ,18 ,146 ,82 ,210 ,50 ,178 ,114 ,242 ,
    10 ,138 ,74 ,202 ,42 ,170 ,106 ,234 ,26 ,154 ,90 ,218 ,58 ,186 ,122 ,250 ,
    6 ,134 ,70 ,198 ,38 ,166 ,102 ,230 ,22 ,150 ,86 ,214 ,54 ,182 ,118 ,246 ,
    14 ,142 ,78 ,206 ,46 ,174 ,110 ,238 ,30 ,158 ,94 ,222 ,62 ,190 ,126 ,254 ,
    1 ,129 ,65 ,193 ,33 ,161 ,97 ,225 ,17 ,145 ,81 ,209 ,49 ,177 ,113 ,241 ,
    9 ,137 ,73 ,201 ,41 ,169 ,105 ,233 ,25 ,153 ,89 ,217 ,57 ,185 ,121 ,249 ,
    5 ,133 ,69 ,197 ,37 ,165 ,101 ,229 ,21 ,149 ,85 ,213 ,53 ,181 ,117 ,245 ,
    13 ,141 ,77 ,205 ,45 ,173 ,109 ,237 ,29 ,157 ,93 ,221 ,61 ,189 ,125 ,253 ,
    3 ,131 ,67 ,195 ,35 ,163 ,99 ,227 ,19 ,147 ,83 ,211 ,51 ,179 ,115 ,243 ,
    11 ,139 ,75 ,203 ,43 ,171 ,107 ,235 ,27 ,155 ,91 ,219 ,59 ,187 ,123 ,251 ,
    7 ,135 ,71 ,199 ,39 ,167 ,103 ,231 ,23 ,151 ,87 ,215 ,55 ,183 ,119 ,247 ,
    15 ,143 ,79 ,207 ,47 ,175 ,111 ,239 ,31 ,159 ,95 ,223 ,63 ,191 ,127 ,255 ,
};


const float square_verts[18] =
{
    -1,  1, 0,     // 左上角
    -1,  -1, 0,     // 左下角
    1,  -1, 0,     // 右下角

    1,  -1, 0,     // 右下角
    1,  1, 0,     // 右上角
    -1,  1, 0,     // 左上角
};


const char* const commonVertShaderCode = {
    "#version 320 es\n"
    "\n"
    "layout(location = 0) in vec3 vPos;\n"
    "\n"
    "void main()\n"
    "{\n"
    "    gl_Position = vec4(vPos,1);\n"
    "}\n"
};

const char* const commonExtVertShaderCode = {
    "#version 320 es\n"
    "\n"
    "layout(location = 0) in vec3 vPos;\n"
    "\n"
    "layout(location = 40) uniform mat4 projViewMat;\n"
    "layout(location = 41) uniform mat4 modelMat;\n"
    "\n"
    "out vec2 vertTexCoord;\n"
    "\n"
    "void main()\n"
    "{\n"
    "    gl_Position = projViewMat * modelMat * vec4(vPos,1);\n"
    "    vertTexCoord = gl_Position.xy/gl_Position.w;\n"
    "    vertTexCoord = (vertTexCoord + 1.0f) / 2.0f;\n"
    "}\n"
};

const char* const cvtUItoFloatFragShaderCode = {
    "#version 320 es\n"
    "\n"
    //"//着色器语言标准 参考 https://www.khronos.org/registry/OpenGL/specs/es/3.1/GLSL_ES_Specification_3.10.pdf\n"
    "\n"
    //"//gl es 3.1的精度标准：highp:32bit, mediump:16~32bit, lowp:9~32位\n"
    "precision highp float; \n" //gl es要求显式定义 默认float类型精度
    "\n"
    //"//float 对应samplerXX, unsigned interger 对应 usamplerXX, signed interger 对应 isamplerXX\n"
    "layout(location = 0) uniform highp usampler2D tex_input;\n"
    "\n"
    "layout(location = 20) uniform highp float multi_alpha;\n"
    "layout(location = 21) uniform highp float add_beta;\n"
    "\n"
    //"//  输出也要与 线定Attachment的纹理类型相同， vecx -> float, uvecx -> unsigned int, ivecx-> signed int\n"
    "out highp vec4 FragColor;\n"
    "void main()\n"
    "{\n"
    "    uvec4 value = texelFetch(tex_input,ivec2(gl_FragCoord.xy),0);\n"
    "    FragColor = multi_alpha * vec4(value) + add_beta;// vec4(value)/255.0f;\n"
    "}\n"
};


const char* const cvtFloatToUIFragShaderCode = {
    "#version 320 es\n"
    "precision highp float; \n"
    "layout(location = 0) uniform highp sampler2D tex_input;\n"
    "layout(location = 20) uniform highp float multi_alpha;\n"
    "layout(location = 21) uniform highp float add_beta;\n"
    "\n"
    "out highp uvec4 FragColor;\n"
    "void main()\n"
    "{\n"
    "    vec4 value = texelFetch(tex_input,ivec2(gl_FragCoord.xy),0); \n"
    "    value = multi_alpha * value + add_beta; \n"
    "    FragColor = uvec4(value); \n"
    "}\n"
};


const char* const textureCopyShaderCode = {
    "#version 320 es\n"
    "precision highp float; \n"
    "layout(location = 0) uniform highp sampler2D tex_input;\n"
    "layout(location = 1) uniform highp usampler2D utex_input;\n"
    "layout(location = 2) uniform highp isampler2D itex_input;\n"
    "layout(location = 20) uniform highp float multi_alpha;\n"
    "layout(location = 21) uniform highp float add_beta;\n"
    "layout(location = 22) uniform lowp ivec2 iotype;\n" //type.x输入的纹理数据类型 type.y输出的纹理数据类型
    "\n"
    "layout(location = 0) out highp vec4 FragColor;\n"
    "layout(location = 1) out highp uvec4 uFragColor;\n"
    "layout(location = 2) out highp ivec4 iFragColor;\n"
    "void main()\n"
    "{\n"
    "    vec4 value;\n"
    "    if(iotype.x == 0) value = texelFetch(tex_input,ivec2(gl_FragCoord.xy),0); \n"    //单精度浮点数
    "    else if(iotype.x == 1) value = vec4(texelFetch(utex_input,ivec2(gl_FragCoord.xy),0)); \n"    //无符号整数
    "    else if(iotype.x == 2) value = vec4(texelFetch(itex_input,ivec2(gl_FragCoord.xy),0)); \n"    //整数
    "    value = multi_alpha * value + add_beta; \n"     //alpha *value + beta
    "    FragColor = value; \n"  //value  vec4(textureSize(itex_input,0).y)
    "    uFragColor = uvec4(value); \n"
    "    iFragColor = ivec4(value); \n"
    "}\n"
};

const char* const textureCopySrcShaderCode = {
    "#version 320 es\n"
    "precision highp float; \n"
    "layout(location = 0) uniform highp sampler2D tex_input;\n"
    "layout(location = 1) uniform highp usampler2D utex_input;\n"
    "layout(location = 2) uniform highp isampler2D itex_input;\n"
    "layout(location = 22) uniform lowp ivec2 iotype;\n" //type.x输入的纹理数据类型 type.y输出的纹理数据类型
    "layout(location = 23) uniform mediump ivec2 ioffset;\n"
    "\n"
    "layout(location = 0) out highp vec4 FragColor;\n"
    "layout(location = 1) out highp uvec4 uFragColor;\n"
    "layout(location = 2) out highp ivec4 iFragColor;\n"
    "void main()\n"
    "{\n"
    "    ivec2 pos = ivec2(gl_FragCoord.xy) - ioffset; \n"
    "    ivec2 size = int(iotype.x == 0)*textureSize(tex_input,0) + int(iotype.x == 1)*textureSize(utex_input,0) + int(iotype.x == 2)*textureSize(itex_input,0); \n"
    "    if(pos.x<0 || pos.y<0 || pos.x>=size.x || pos.y>=size.y) {discard;return;}\n"   //超出范围放弃写入
    "    vec4 value;\n"
    "    if(iotype.x == 0) value = texelFetch(tex_input,pos,0); \n"    //单精度浮点数
    "    else if(iotype.x == 1) value = vec4(texelFetch(utex_input,pos,0)); \n"    //无符号整数
    "    else if(iotype.x == 2) value = vec4(texelFetch(itex_input,pos,0)); \n"    //整数
    "    FragColor = value; \n" //value
    "    uFragColor = uvec4(value); \n"
    "    iFragColor = ivec4(value); \n"
    "}\n"
};


const char* const splitTextureUI =
{
    "#version 320 es\n"
    "precision highp float;\n"
    "\n"
    "layout(location = 0) uniform highp usampler2D utex_input;\n"
    "\n"
    "layout(location = 0) out highp uint uFragCHR;\n"
    "layout(location = 1) out highp uint uFragCHG;\n"
    "layout(location = 2) out highp uint uFragCHB;\n"
    "layout(location = 3) out highp uint uFragCHA;\n"
    "void main()\n"
    "{\n"
    "    uvec4 value = texelFetch(utex_input,ivec2(gl_FragCoord.xy),0);\n"
    "    uFragCHR = value.r;\n"
    "    uFragCHG = value.g;\n"
    "    uFragCHB = value.b;\n"
    "    uFragCHA = value.a;\n"
    "}\n"
};

const char* const splitTextureINT=
{
    "#version 320 es\n"
    "precision highp float;\n"
    "\n"
    "layout(location = 0) uniform highp isampler2D itex_input;\n"
    "\n"
    "layout(location = 0) out highp int iFragCHR;\n"
    "layout(location = 1) out highp int iFragCHG;\n"
    "layout(location = 2) out highp int iFragCHB;\n"
    "layout(location = 3) out highp int iFragCHA;\n"
    "void main()\n"
    "{\n"
    "    ivec4 value = texelFetch(itex_input,ivec2(gl_FragCoord.xy),0);\n"
    "    iFragCHR = value.r;\n"
    "    iFragCHG = value.g;\n"
    "    iFragCHB = value.b;\n"
    "    iFragCHA = value.a;\n"
    "}\n"
};

const char* const splitTextureFloat =
{
    "#version 320 es\n"
    "precision highp float;\n"
    "\n"
    "layout(location = 0) uniform highp sampler2D tex_input;\n"
    "\n"
    "layout(location = 0) out highp float FragCHR;\n"
    "layout(location = 1) out highp float FragCHG;\n"
    "layout(location = 2) out highp float FragCHB;\n"
    "layout(location = 3) out highp float FragCHA;\n"
    "void main()\n"
    "{\n"
    "    vec4 value = texelFetch(tex_input,ivec2(gl_FragCoord.xy),0);\n"
    "    FragCHR = value.r;\n"
    "    FragCHG = value.g;\n"
    "    FragCHB = value.b;\n"
    "    FragCHA = value.a;\n"
    "}\n"
};

const char* const mergeTexturesUI =
{
    "#version 320 es\n"
    "precision highp float;\n"
    "\n"
    "layout(location = 0) uniform highp usampler2D utex_inputCHR;\n"
    "layout(location = 1) uniform highp usampler2D utex_inputCHG;\n"
    "layout(location = 2) uniform highp usampler2D utex_inputCHB;\n"
    "layout(location = 3) uniform highp usampler2D utex_inputCHA;\n"
    "\n"
    "layout(location = 0) out highp uvec4 uFragColor;\n"
    "\n"
    "void main()\n"
    "{\n"
    "    uint rvalue = texelFetch(utex_inputCHR,ivec2(gl_FragCoord.xy),0).r;\n"
    "    uint gvalue = texelFetch(utex_inputCHG,ivec2(gl_FragCoord.xy),0).r;\n"
    "    uint bvalue = texelFetch(utex_inputCHB,ivec2(gl_FragCoord.xy),0).r;\n"
    "    uint avalue = texelFetch(utex_inputCHA,ivec2(gl_FragCoord.xy),0).r;\n"
    "    uFragColor = uvec4(rvalue,gvalue,bvalue,avalue);\n"
    "}\n"
};

const char* const mergeTexturesINT =
{
    "#version 320 es\n"
    "precision highp float;\n"
    "\n"
    "layout(location = 0) uniform highp isampler2D itex_inputCHR;\n"
    "layout(location = 1) uniform highp isampler2D itex_inputCHG;\n"
    "layout(location = 2) uniform highp isampler2D itex_inputCHB;\n"
    "layout(location = 3) uniform highp isampler2D itex_inputCHA;\n"
    "\n"
    "layout(location = 0) out highp ivec4 iFragColor;\n"
    "\n"
    "void main()\n"
    "{\n"
    "    int rvalue = texelFetch(itex_inputCHR,ivec2(gl_FragCoord.xy),0).r;\n"
    "    int gvalue = texelFetch(itex_inputCHG,ivec2(gl_FragCoord.xy),0).r;\n"
    "    int bvalue = texelFetch(itex_inputCHB,ivec2(gl_FragCoord.xy),0).r;\n"
    "    int avalue = texelFetch(itex_inputCHA,ivec2(gl_FragCoord.xy),0).r;\n"
    "    iFragColor = ivec4(rvalue,gvalue,bvalue,avalue);\n"
    "}\n"
};


const char* const mergeTexturesFloat =
{
    "#version 320 es\n"
    "precision highp float;\n"
    "\n"
    "layout(location = 0) uniform highp sampler2D tex_inputCHR;\n"
    "layout(location = 1) uniform highp sampler2D tex_inputCHG;\n"
    "layout(location = 2) uniform highp sampler2D tex_inputCHB;\n"
    "layout(location = 3) uniform highp sampler2D tex_inputCHA;\n"
    "\n"
    "layout(location = 0) out highp vec4 FragColor;\n"
    "\n"
    "void main()\n"
    "{\n"
    "    float rvalue = texelFetch(tex_inputCHR,ivec2(gl_FragCoord.xy),0).r;\n"
    "    float gvalue = texelFetch(tex_inputCHG,ivec2(gl_FragCoord.xy),0).r;\n"
    "    float bvalue = texelFetch(tex_inputCHB,ivec2(gl_FragCoord.xy),0).r;\n"
    "    float avalue = texelFetch(tex_inputCHA,ivec2(gl_FragCoord.xy),0).r;\n"
    "    FragColor = vec4(rvalue,gvalue,bvalue,avalue);\n"
    "}\n"
};

const char* const tex2DcvtGrayscaleFShaderCode = {
    "#version 320 es\n"
    "precision highp float;\n"
    "\n"
    "layout(location = 0) uniform highp sampler2D tex_input;\n"
    "layout(location = 1) uniform highp usampler2D utex_input;\n"
    "layout(location = 2) uniform highp isampler2D itex_input;\n"
    "\n"
    "layout(location = 20) uniform lowp ivec2 iotype;\n" //type.x输入的纹理数据类型 type.y输出的纹理数据类型
    "layout(location = 21) uniform lowp int hasalpha;\n"
    "\n"
    "layout(location = 0) out highp vec4 FragColor;\n"
    "layout(location = 1) out highp uvec4 uFragColor;\n"
    "layout(location = 2) out highp ivec4 iFragColor;\n"
    "\n"
    "void main()\n"
    "{\n"
    "    highp vec4 value;\n"
    "    if(iotype.x == 0) value = texelFetch(tex_input,ivec2(gl_FragCoord.xy),0); \n"    //单精度浮点数
    "    else if(iotype.x == 1) value = vec4(texelFetch(utex_input,ivec2(gl_FragCoord.xy),0)); \n"    //无符号整数
    "    else if(iotype.x == 2) value = vec4(texelFetch(itex_input,ivec2(gl_FragCoord.xy),0)); \n"    //整数
    "    if(hasalpha != 0) value.rgb = value.rgb * value.a;\n"
    "    value.r = 0.3f * value.r + 0.59f * value.g + 0.11f * value.b;\n"   //转换为灰度
    "    FragColor = vec4(value.r);\n"
    "    uFragColor = uvec4(value.r);\n"
    "    iFragColor = ivec4(value.r);\n"
    "}\n"
};

const char* const tex2DcvtColorFShaderCode = {
    "#version 320 es\n"
    "precision highp float;\n"
    "\n"
    "layout(location = 0) uniform highp sampler2D tex_input;\n"
    "layout(location = 1) uniform highp usampler2D utex_input;\n"
    "layout(location = 2) uniform highp isampler2D itex_input;\n"
    "layout(location = 5) uniform highp sampler2D colormap;\n"
    "\n"
    "layout(location = 20) uniform lowp ivec2 iotype;\n" //type.x输入的纹理数据类型 type.y输出的纹理数据类型
    "layout(location = 21) uniform highp float maxval;\n"  //颜色映射表长度
    "\n"
    "layout(location = 0) out highp vec4 FragColor;\n"
    "layout(location = 1) out highp uvec4 uFragColor;\n"
    "layout(location = 2) out highp ivec4 iFragColor;\n"
    "\n"
    "void main()\n"
    "{\n"
    "    highp vec4 value;\n"
    "    if(iotype.x == 0) value = texelFetch(tex_input,ivec2(gl_FragCoord.xy),0); \n"    //单精度浮点数
    "    else if(iotype.x == 1) value = vec4(texelFetch(utex_input,ivec2(gl_FragCoord.xy),0)); \n"    //无符号整数
    "    else if(iotype.x == 2) value = vec4(texelFetch(itex_input,ivec2(gl_FragCoord.xy),0)); \n"    //整数
    "    value.r = value.r / maxval;\n"
    "    value = texture(colormap, vec2(value.r,0));\n"   //查找对应的彩色值
    "    FragColor = value;\n"
    "    uFragColor = uvec4(value);\n"
    "    iFragColor = ivec4(value);\n"
    "}\n"
};

const char* const tex2DWinTo = {
    "#version 320 es\n"
    "precision highp float;\n"
    "\n"
    "layout(location = 0) uniform highp sampler2D tex_input;\n"
    "layout(location = 1) uniform highp usampler2D utex_input;\n"
    "layout(location = 2) uniform highp isampler2D itex_input;\n"
    "\n"
    "layout(location = 20) uniform lowp int itype;\n" // 输入的纹理数据类型 0:浮点, 1:无符号整数 2:整数
    "layout(location = 21) uniform highp vec3 win;\n"  //win.x窗变换的起始值 win.y窗变换的结束值 win.z窗变换的缩放比例
    "\n"
    "layout(location = 0) out highp vec4 FragColor;\n"
    "layout(location = 1) out highp uvec4 uFragColor;\n"
    "layout(location = 2) out highp ivec4 iFragColor;\n"
    "\n"
    "void main()\n"
    "{\n"
    "    highp vec4 value;\n"
    "    if(itype == 0) value = texelFetch(tex_input,ivec2(gl_FragCoord.xy),0); \n"    //单精度浮点数
    "    else if(itype == 1) value = vec4(texelFetch(utex_input,ivec2(gl_FragCoord.xy),0)); \n"    //无符号整数
    "    else if(itype == 2) value = vec4(texelFetch(itex_input,ivec2(gl_FragCoord.xy),0)); \n"    //整数
    //超出窗范围时钳位
    "    value = vec4(lessThan(value,vec4(win.x))) * vec4(win.x) + vec4(greaterThanEqual(value,vec4(win.x))) * value;\n"
    "    value = vec4(greaterThan(value,vec4(win.y))) * vec4(win.y) + vec4(lessThanEqual(value,vec4(win.y))) * value;\n"
    //变换成指定的范围
    "    value = value - win.x;\n"
    "    value = value / (win.y - win.x);\n"
    "    value = value * win.z;\n"
    "    FragColor = value;\n"
    "    uFragColor = uvec4(value);\n"
    "    iFragColor = ivec4(value);\n"
    "}\n"
};


const char* const textureThresholdUI =
{
    "#version 320 es\n"
    "precision highp float;\n"
    "\n"
    "layout(location = 0) uniform highp usampler2D utex_input;\n"
    "\n"
    "#define THRESH_BINARY 0\n"
    "#define THRESH_BINARY_INV 1\n"
    "#define THRESH_TRUNC 2\n"
    "#define THRESH_TOZERO 3\n"
    "#define THRESH_TOZERO_INV 4\n"
    "#define THRESH_RANGE 5\n"
    "\n"
    "layout(location = 20) uniform lowp int threstype;\n"
    "layout(location = 21) uniform highp uvec4 thresh;\n"
    "layout(location = 22) uniform highp uvec4 maxval;\n"
    "\n"
    "\n"
    "layout(location = 0) out highp uvec4 uFragColor;\n"
    "\n"
    "void main()\n"
    "{\n"
    "    uvec4 value = texelFetch(utex_input,ivec2(gl_FragCoord.xy),0);\n"
    "    uvec4 sumVal = uint(threstype==THRESH_BINARY) * uvec4(greaterThan(value,thresh)) * maxval;\n"
    "    sumVal = sumVal + uint(threstype==THRESH_BINARY_INV) * uvec4(lessThanEqual(value,thresh)) * maxval;\n"
    "    sumVal = sumVal + uint(threstype==THRESH_TRUNC) * (uvec4(greaterThan(value,thresh)) * thresh + uvec4(lessThanEqual(value,thresh)) * value);\n"
    "    sumVal = sumVal + uint(threstype==THRESH_TOZERO) * uvec4(greaterThan(value,thresh)) * value;\n"
    "    sumVal = sumVal + uint(threstype==THRESH_TOZERO_INV) * uvec4(lessThanEqual(value,thresh)) * value;\n"
    "    sumVal = sumVal + uint(threstype==THRESH_RANGE) * uvec4(greaterThanEqual(value,thresh)) * uvec4(lessThanEqual(value,maxval)) * value;\n"
    "    uFragColor = sumVal;\n"
    "}\n"
};

const char* const textureThresholdINT =
{
    "#version 320 es\n"
    "precision highp float;\n"
    "\n"
    "layout(location = 0) uniform highp isampler2D itex_input;\n"
    "\n"
    "#define THRESH_BINARY 0\n"
    "#define THRESH_BINARY_INV 1\n"
    "#define THRESH_TRUNC 2\n"
    "#define THRESH_TOZERO 3\n"
    "#define THRESH_TOZERO_INV 4\n"
    "#define THRESH_RANGE 5\n"
    "\n"
    "layout(location = 20) uniform lowp int threstype;\n"
    "layout(location = 21) uniform highp ivec4 thresh;\n"
    "layout(location = 22) uniform highp ivec4 maxval;\n"
    "\n"
    "\n"
    "layout(location = 0) out highp ivec4 iFragColor;\n"
    "\n"
    "void main()\n"
    "{\n"
    "    ivec4 value = texelFetch(itex_input,ivec2(gl_FragCoord.xy),0);\n"
    "    ivec4 sumVal = int(threstype==THRESH_BINARY) * ivec4(greaterThan(value,thresh)) * maxval;\n"
    "    sumVal = sumVal + int(threstype==THRESH_BINARY_INV) * ivec4(lessThanEqual(value,thresh)) * maxval;\n"
    "    sumVal = sumVal + int(threstype==THRESH_TRUNC) * (ivec4(greaterThan(value,thresh)) * thresh + ivec4(lessThanEqual(value,thresh)) * value);\n"
    "    sumVal = sumVal + int(threstype==THRESH_TOZERO) * ivec4(greaterThan(value,thresh)) * value;\n"
    "    sumVal = sumVal + int(threstype==THRESH_TOZERO_INV) * ivec4(lessThanEqual(value,thresh)) * value;\n"
    "    sumVal = sumVal + int(threstype==THRESH_RANGE) * ivec4(greaterThanEqual(value,thresh)) * ivec4(lessThanEqual(value,maxval)) * value;\n"
    "    iFragColor = sumVal;\n"
    "}\n"
};

const char* const textureThresholdFloat =
{
    "#version 320 es\n"
    "precision highp float;\n"
    "\n"
    "layout(location = 0) uniform highp sampler2D tex_input;\n"
    "\n"
    "#define THRESH_BINARY 0\n"
    "#define THRESH_BINARY_INV 1\n"
    "#define THRESH_TRUNC 2\n"
    "#define THRESH_TOZERO 3\n"
    "#define THRESH_TOZERO_INV 4\n"
    "#define THRESH_RANGE 5\n"
    "\n"
    "layout(location = 20) uniform lowp int threstype;\n"
    "layout(location = 21) uniform highp vec4 thresh;\n"
    "layout(location = 22) uniform highp vec4 maxval;\n"
    "\n"
    "\n"
    "layout(location = 0) out highp vec4 FragColor;\n"
    "\n"
    "void main()\n"
    "{\n"
    "    vec4 value = texelFetch(tex_input,ivec2(gl_FragCoord.xy),0);\n"
    "    vec4 sumVal = float(threstype==THRESH_BINARY) * vec4(greaterThan(value,thresh)) * maxval;\n"
    "    sumVal = sumVal + float(threstype==THRESH_BINARY_INV) * vec4(lessThanEqual(value,thresh)) * maxval;\n"
    "    sumVal = sumVal + float(threstype==THRESH_TRUNC) * (vec4(greaterThan(value,thresh)) * thresh + vec4(lessThanEqual(value,thresh)) * value);\n"
    "    sumVal = sumVal + float(threstype==THRESH_TOZERO) * vec4(greaterThan(value,thresh)) * value;\n"
    "    sumVal = sumVal + float(threstype==THRESH_TOZERO_INV) * vec4(lessThanEqual(value,thresh)) * value;\n"
    "    sumVal = sumVal + float(threstype==THRESH_RANGE) * vec4(greaterThanEqual(value,thresh)) * vec4(lessThanEqual(value,maxval)) * value;\n"
    "    FragColor = sumVal;\n"
    "}\n"
};

const char* const textureRegionOfInterest = {
    "#version 320 es\n"
    "precision highp float;\n"
    "\n"
    "layout(location = 0) uniform highp sampler2D tex_input;\n"
    "layout(location = 1) uniform highp usampler2D utex_input;\n"
    "layout(location = 2) uniform highp isampler2D itex_input;\n"
    "\n"
    "layout(location = 20) uniform mediump ivec2 ioffset;\n"
    "\n"
    "layout(location = 0) out highp vec4 FragColor;\n"
    "layout(location = 1) out highp uvec4 uFragColor;\n"
    "layout(location = 2) out highp ivec4 iFragColor;\n"
    "\n"
    "void main()\n"
    "{\n"
    "    FragColor = texelFetch(tex_input,ivec2(gl_FragCoord.xy)+ioffset,0);\n"
    "    uFragColor = texelFetch(utex_input,ivec2(gl_FragCoord.xy)+ioffset,0);\n"
    "    iFragColor = texelFetch(itex_input,ivec2(gl_FragCoord.xy)+ioffset,0);\n"
    "}\n"
};


const char* const texelMath = {
    "#version 320 es\n"
    "\n"
    "#define GLGP_TEXELMATH_LINEAR 0\n"
    "#define GLGP_TEXELMATH_POW 1\n"
    "#define GLGP_TEXELMATH_EXP 2\n"
    "#define GLGP_TEXELMATH_EXP2 3\n"
    "#define GLGP_TEXELMATH_LOG 4\n"
    "#define GLGP_TEXELMATH_LOG2 5\n"
    "#define GLGP_TEXELMATH_AMPLITUDE 6\n"
    "\n"
    "precision highp float;\n"
    "\n"
    "layout(location = 0) uniform highp sampler2D tex_input;\n"
    "layout(location = 1) uniform highp usampler2D utex_input;\n"
    "layout(location = 2) uniform highp isampler2D itex_input;\n"
    "\n"
    "layout(location = 20) uniform highp float alpha;\n"
    "layout(location = 21) uniform highp float beta;\n"
    "layout(location = 22) uniform lowp ivec2 iotype;\n" //type.x输入的纹理数据类型 type.y输出的纹理数据类型
    "layout(location = 23) uniform lowp int mathtype;\n"
    "\n"
    "layout(location = 0) out highp vec4 FragColor;\n"
    "layout(location = 1) out highp uvec4 uFragColor;\n"
    "layout(location = 2) out highp ivec4 iFragColor;\n"
    "\n"
    "void main()\n"
    "{\n"
    "    vec4 value;\n"
    "    if(iotype.x == 0) value = texelFetch(tex_input,ivec2(gl_FragCoord.xy),0); \n"    //单精度浮点数
    "    else if(iotype.x == 1) value = vec4(texelFetch(utex_input,ivec2(gl_FragCoord.xy),0)); \n"    //无符号整数
    "    else if(iotype.x == 2) value = vec4(texelFetch(itex_input,ivec2(gl_FragCoord.xy),0)); \n"    //整数
    "    if(mathtype == GLGP_TEXELMATH_LINEAR) value = alpha * value + beta;\n"
    "    else if(mathtype == GLGP_TEXELMATH_POW) value = vec4( pow(value.r,alpha),pow(value.g,alpha),pow(value.b,alpha),pow(value.a,alpha) );\n"
    "    else if(mathtype == GLGP_TEXELMATH_EXP) value = vec4( exp(value.r),exp(value.g),exp(value.b),exp(value.a) );\n"
    "    else if(mathtype == GLGP_TEXELMATH_EXP2) value = vec4( exp2(value.r),exp2(value.g),exp2(value.b),exp2(value.a) );\n"
    "    else if(mathtype == GLGP_TEXELMATH_LOG) value = vec4( log(value.r),log(value.g),log(value.b),log(value.a) );\n"
    "    else if(mathtype == GLGP_TEXELMATH_LOG2) value = vec4( log2(value.r),log2(value.g),log2(value.b),log2(value.a) );\n"
    "    else if(mathtype == GLGP_TEXELMATH_AMPLITUDE) value = vec4( alpha * pow(pow(value.r,2.0f)+pow(value.g,2.0f),0.5f) + beta, value.g, value.b, value.a );\n"
    "    FragColor = vec4(value);\n"
    "    uFragColor = uvec4(value);\n"
    "    iFragColor = ivec4(value);\n"
    "}\n"
};

const char* const texturesMath = {
    "#version 320 es\n"
    "\n"
    "#define MATH_ADD 0\n"
    "#define MATH_SUB 1\n"
    "#define MATH_MUL 2\n"
    "#define MATH_DIV 3\n"
    "#define MATH_AMPLITUDE 4\n"
    "\n"
    "precision highp float;\n"
    "\n"
    "layout(location = 0) uniform highp sampler2D tex_input;\n"
    "layout(location = 1) uniform highp usampler2D utex_input;\n"
    "layout(location = 2) uniform highp isampler2D itex_input;\n"
    "layout(location = 3) uniform highp sampler2D tex1_input;\n"
    "layout(location = 4) uniform highp usampler2D utex1_input;\n"
    "layout(location = 5) uniform highp isampler2D itex1_input;\n"
    "\n"
    "layout(location = 22) uniform lowp int itype;\n"   //输入纹理的数据类型 0 float ,1 unsigned int,2 int
    "layout(location = 23) uniform lowp int mathtype;\n"
    "\n"
    "layout(location = 0) out highp vec4 FragColor;\n"
    "layout(location = 1) out highp uvec4 uFragColor;\n"
    "layout(location = 2) out highp ivec4 iFragColor;\n"
    "\n"
    "void main()\n"
    "{\n"
    "    vec4 value;\n"
    "    if(itype == 0) value = texelFetch(tex_input,ivec2(gl_FragCoord.xy),0);\n "
    "    else if(itype == 1) value = vec4(texelFetch(utex_input,ivec2(gl_FragCoord.xy),0));\n "
    "    else if(itype == 2) value = vec4(texelFetch(itex_input,ivec2(gl_FragCoord.xy),0));\n"
    "    vec4 value1 = float(itype == 0) * texelFetch(tex1_input,ivec2(gl_FragCoord.xy),0);\n "
    "    value1 = value1 + float(itype == 1) * vec4(texelFetch(utex1_input,ivec2(gl_FragCoord.xy),0));\n "
    "    value1 = value1 + float(itype == 2) * vec4(texelFetch(itex1_input,ivec2(gl_FragCoord.xy),0));\n"
    " \n"
    "    if(mathtype == MATH_ADD) value = value + value1;"
    "    else if(mathtype == MATH_SUB) value = value - value1;"
    "    else if(mathtype == MATH_MUL) value = value * value1;"
    "    else if(mathtype == MATH_DIV) value = value / value1;"
    "    else if(mathtype == MATH_AMPLITUDE) {\n"
    "       value = value * value + value1 * value1;\n"
    "       value = vec4( sqrt(value.r),sqrt(value.g),sqrt(value.b),sqrt(value.a) );\n"
    "    }\n"
    "    FragColor = value;\n"
    "    uFragColor = uvec4(value);\n"
    "    iFragColor = ivec4(value);\n"
    "}\n"
};


const char* const resizeTextureStr = {
    "#version 320 es\n"
    "precision highp float;\n"
    "\n"
    "layout(location = 0) uniform highp sampler2D tex_input;\n"
//    "layout(location = 1) uniform highp usampler2D utex_input;\n"
//    "layout(location = 2) uniform highp isampler2D itex_input;\n"
    "\n"
    "layout(location = 20) uniform mediump vec2 fsize;\n"
    "\n"
    "layout(location = 0) out highp vec4 FragColor;\n"
    "layout(location = 1) out highp uvec4 uFragColor;\n"
    "layout(location = 2) out highp ivec4 iFragColor;\n"
    "\n"
    "void main()\n"
    "{\n"
    "    vec2 pos = vec2(ivec2(gl_FragCoord.xy)) / (fsize - 1.0f);\n"     //要考虑半格效应,将位置化为0~1范围
    "    FragColor = texture(tex_input,pos);\n"
    "    uFragColor = uvec4( FragColor );\n"
    "    iFragColor = ivec4( FragColor );\n"
    "}\n"
};


const char* const textureTransformVertShader = { //2DPerspective
    "#version 320 es\n"
    "\n"
    "layout(location = 0) in vec3 vPos;\n"
    "\n"
//    "layout(location = 40) uniform highp mat3 projMat;\n"
//    "layout(location = 41) uniform highp mat3 viewMat;\n"
//    "layout(location = 42) uniform highp mat3 modelMat;\n"
    "\n"
//    "out highp vec3 texelCoord;\n"
//    "out flat highp mat3 inverseViewMat;\n"
    "\n"
    "void main()\n"
    "{\n"
//    "    texelCoord = inverse(viewMat) * modelMat * vec3(vPos.xy,1);\n"  //计算出映射源纹理的坐标
//    "    inverseViewMat = inverse(viewMat);\n"   // 输出映射矩阵的逆矩阵
    "    gl_Position = vec4(vPos,1);\n;"              //输出顶点坐标
    "}\n"
};

const char* const textureTransformFragShader = {
    "#version 320 es\n"
    "precision highp float;\n"
    "\n"
//    "in highp vec3 texelCoord;\n"
//    "in flat highp mat3 inverseViewMat;\n"
    "\n"
    "layout(location = 0) uniform highp sampler2D tex_input;\n"
    "layout(location = 1) uniform highp usampler2D utex_input;\n"
    "layout(location = 2) uniform highp isampler2D itex_input;\n"
    "\n"
    "layout(location = 20) uniform highp ivec2 texsize;\n"
    "layout(location = 21) uniform lowp int itype;\n"     //输入纹理的类型 0:32位浮点 1:无符号整数 2:整数
    "layout(location = 41) uniform highp mat3 transMat;\n"  //直接用变换矩阵的逆矩阵来计算
    "\n"
    "layout (binding = 0, rgba32f) highp uniform image2D FragColor;\n"   //gl es必须指明精度
    "\n"
    "void main()\n"
    "{\n"   //15
    "    vec4 texel = vec4(0);\n"   //纹理像素累加值
    //inverseViewMat
    "    vec3 weightfract = transMat * vec3(gl_FragCoord.xy - 0.5f,1);\n" // 由映射坐标转为源平面坐标;减去0.5是因为gl_FragCoord对应 (0.5,width-0.5)和(0.5,height-0.5); //texelCoord / texelCoord.z;
    "    weightfract = weightfract / weightfract.z;\n"    //由映射坐标转为平面坐标;
    "    ivec2 texelpos = ivec2(floor(weightfract));\n"  //转换为整数坐标
    "    weightfract = fract(weightfract);\n"     //小数数值用作权重
    // 取左下角像素
    "    weightfract.x = 1.0f-weightfract.x;\n"
    "    weightfract.y = 1.0f-weightfract.y;\n"
    "    weightfract.z = weightfract.x * weightfract.y * "
    "       float(all(bvec2(ivec2(greaterThanEqual(texelpos,ivec2(0))) * ivec2(lessThan(texelpos,texsize)))));\n"
    "    if(itype==0) texel = texel + weightfract.z * texelFetch( tex_input, texelpos, 0 );\n"
    "    else if(itype==1) texel = texel + weightfract.z * vec4(texelFetch(utex_input, texelpos, 0 ));\n"
    "    else if(itype==2) texel = texel + weightfract.z * vec4(texelFetch(itex_input, texelpos, 0 ));\n"
    // 取右下角像素
    "    texelpos.x = texelpos.x + 1;\n"
    "    weightfract.x = 1.0f-weightfract.x;\n"
    "    weightfract.z = weightfract.x * weightfract.y * "
    "       float(all(bvec2(ivec2(greaterThanEqual(texelpos,ivec2(0))) * ivec2(lessThan(texelpos,texsize)))));\n"
    "    if(itype==0) texel = texel + weightfract.z * texelFetch( tex_input, texelpos, 0 );\n"
    "    else if(itype==1) texel = texel + weightfract.z * vec4(texelFetch(utex_input, texelpos, 0 ));\n"
    "    else if(itype==2) texel = texel + weightfract.z * vec4(texelFetch(itex_input, texelpos, 0 ));\n"
    // 取右上角像素
    "    texelpos.y = texelpos.y + 1;\n"
    "    weightfract.y = 1.0f-weightfract.y;\n"
    "    weightfract.z = weightfract.x * weightfract.y * "
    "       float(all(bvec2(ivec2(greaterThanEqual(texelpos,ivec2(0))) * ivec2(lessThan(texelpos,texsize)))));\n"
    "    if(itype==0) texel = texel + weightfract.z * texelFetch( tex_input, texelpos, 0 );\n"
    "    else if(itype==1) texel = texel + weightfract.z * vec4(texelFetch(utex_input, texelpos, 0 ));\n"
    "    else if(itype==2) texel = texel + weightfract.z * vec4(texelFetch(itex_input, texelpos, 0 ));\n"
    // 取左上角像素
    "    texelpos.x = texelpos.x - 1;\n"
    "    weightfract.x = 1.0f-weightfract.x;\n"
    "    weightfract.z = weightfract.x * weightfract.y * "
    "       float(all(bvec2(ivec2(greaterThanEqual(texelpos,ivec2(0))) * ivec2(lessThan(texelpos,texsize)))));\n"
    "    if(itype==0) texel = texel + weightfract.z * texelFetch( tex_input, texelpos, 0 );\n"
    "    else if(itype==1) texel = texel + weightfract.z * vec4(texelFetch(utex_input, texelpos, 0 ));\n"
    "    else if(itype==2) texel = texel + weightfract.z * vec4(texelFetch(itex_input, texelpos, 0 ));\n"

    "    imageStore(FragColor,ivec2(gl_FragCoord.xy),texel);\n" //放置到结果image中
//    "   if(texelpos.y==(texsize.y-1)) imageStore(FragColor,ivec2(gl_FragCoord.xy),vec4(0,255,0,255));\n" //用于测试是否能写到纹理的最后一列
//    "   else imageStore(FragColor,ivec2(gl_FragCoord.xy),vec4(255,0,0,255));\n"
    "    discard;\n"  //不向颜色缓冲写入数据
    "}\n"
};


const char* const setFFTInputTexShaderStr = {
    "#version 320 es\n"
    "precision highp float; \n"
    "layout(location = 0) uniform highp sampler2D tex_input;\n"
    "layout(location = 1) uniform highp usampler2D utex_input;\n"
    "layout(location = 2) uniform highp isampler2D itex_input;\n"
    "layout(location = 3) uniform highp sampler2D fftwincol; \n"   //列fft窗口函数数据
    "layout(location = 4) uniform highp sampler2D fftwinrow; \n"   //行fft窗口函数数据
    "\n"
    "layout(location = 21) uniform lowp int winmode;\n"   //乘以窗数据的模式,0:不乘, 1:只乘以列, 2: 只乘以行, 3: 乘以行和乘以列
    "layout(location = 22) uniform lowp int itype;\n"
    "\n"
    "layout (binding = 0, r32f) highp uniform image2D tex_output;\n"
    "void main()\n"
    "{\n"
    "    highp ivec2 pos = ivec2(gl_FragCoord.xy);\n"
    "    vec4 value;\n"
    "    value.zw = vec2(1,0);\n" //读取窗数据
    "    if(winmode == 1) value.zw = texelFetch(fftwincol,ivec2(pos.x,0),0).xy;"
    "    else if(winmode == 2) value.zw = texelFetch(fftwinrow,ivec2(pos.y,0),0).xy;"
    "    else if(winmode == 3) {\n"
    "        value.xy = texelFetch(fftwincol,ivec2(pos.x,0),0).xy;\n"
    "        value.zw = texelFetch(fftwinrow,ivec2(pos.y,0),0).xy;\n"
    "        value.zw = vec2( value.x * value.z - value.y * value.w , value.x * value.w + value.y * value.z);\n"
    "    }\n"
    "    if(itype == 0) value.xy = texelFetch(tex_input,pos,0).xy; \n"    //读取输入数据 单精度浮点数
    "    else if(itype == 1) value.xy =vec4(texelFetch(utex_input,pos,0)).xy; \n"    //无符号整数
    "    else if(itype == 2) value.xy = vec4(texelFetch(itex_input,pos,0)).xy; \n"    //整数
    "    value.xy = vec2( value.x * value.z - value.y * value.w , value.x * value.w + value.y * value.z);  " //复数乘法，乘以窗数据
    "    pos.x = pos.x * 2;\n"
    "    imageStore(tex_output,pos,vec4(value.x));\n" //写入实部
    "    pos.x = pos.x + 1;\n"
    "    imageStore(tex_output,pos,vec4(value.y));\n" //写入虚部
    "    discard;\n"  //不向颜色缓冲写入数据
    "}\n"
};


const char* const getFFTResultTexShaderStr = {
    "#version 320 es\n"
    "precision highp float; \n"
    "layout(location = 0) uniform highp sampler2DArray tex_input;\n"
    "\n"
    "layout(location = 20) uniform lowp int input_index;\n"
    "\n"
    "layout(location = 0) out highp vec2 FragColor;\n"
    "void main()\n"
    "{\n"
    "    highp ivec2 pos = ivec2(gl_FragCoord.xy);\n"
    "    pos.x = pos.x * 2;\n"
    "    FragColor.x = texelFetch(tex_input,ivec3(pos,input_index),0).x; \n"    //取实部
    "    pos.x = pos.x + 1;\n"
    "    FragColor.y = texelFetch(tex_input,ivec3(pos,input_index),0).x; \n"    //取虚部
    "}\n"
};

const char* const compute2DFFTTexShaderStr={
    "#version 320 es\n"
//    "//输入布局限定符声明一个16 X 16(Xl)\n"
//    "//的本地工作组\n"
    "layout (local_size_x = 16, local_size_y = 16) in;\n"
    "\n"
    "layout(location = 0) uniform highp sampler2D WkN;\n"               //fft 正交旋转因子数据
    "layout(location = 1) uniform lowp isampler2D mirrorByteLUT;\n"     //字节镜像查找表
    "\n"
    "layout(location = 20) uniform lowp uint iscoldir;\n"           //是否按列进行变换,0:每行数据进行变换 1:每列数据进行变换
    "layout(location = 21) uniform mediump int bitscount;\n"        //进行变换的数据长度转为 2^N 的N-1值,这个值也是要进行的蝶形计算次数
    "layout(location = 22) uniform lowp int calcbufStarti;\n"        //计算缓冲数组的索引起始值
    "layout(location = 23) uniform mediump uvec2 bufsize;\n"        //用于计算的缓冲区尺寸
    "layout(location = 24) uniform highp float alphaImag;\n"           //在WkN虚部前相乘的数，可用于逆变换（=-1）
    "layout(location = 25) uniform highp float mulConst;\n"              //蝶形变换后除以的常数，可用于使浮点数变小，以提高精度
    "layout(location = 26) uniform mediump int cyc;\n"                     //循环执行本计算着色器的次数
    "\n"
    "layout (binding = 0, r32f) highp uniform image2DArray calcbuf;\n"   //用于计算的缓冲区数组 coherent
    "\n"
    "void main(void)\n"
    "{\n"
//    "    //cyc等于-1表明进行输入数据重排序\n"
    "    if( cyc == -1 && gl_GlobalInvocationID.x < bufsize.x && gl_GlobalInvocationID.y < bufsize.y ){\n"
//    "        //首先进行抽序\n"
    "        highp vec2 complex;\n"
    "        mediump ivec2 srcpos;\n"
    "        srcpos.y = int(iscoldir == 0u) * int(gl_GlobalInvocationID.x)\n"
    "                + int(iscoldir == 1u) * int(gl_GlobalInvocationID.y);\n"
//    "        srcpos.x = -1;\n"
//    "        srcpos.x = srcpos.y << (bitCount(srcpos.x) - bitscount);\n"     //只要最右面的bitscount位数
//    "        srcpos.x = bitfieldReverse(srcpos.x); \n"                  //镜像二进制位
    "        srcpos.x = 0;\n"
//    "        //只进行3次，也就是最大是24位\n"
    "        srcpos.x = texelFetch(mirrorByteLUT,ivec2(srcpos.y & 0x0FF,0),0).x;\n"       //镜像索引得到要抽取的位置
    "        srcpos.x = srcpos.x << 8;\n"
    "        srcpos.y = srcpos.y >> 8;\n"
    "        srcpos.x = srcpos.x | texelFetch(mirrorByteLUT,ivec2(srcpos.y & 0x0FF,0),0).x;\n"
    "        srcpos.x = srcpos.x << 8;\n"
    "        srcpos.y = srcpos.y >> 8;\n"
    "        srcpos.x = srcpos.x | texelFetch(mirrorByteLUT,ivec2(srcpos.y & 0x0FF,0),0).x;\n"
    "        srcpos.x = srcpos.x >> (24 - bitscount);\n"     //只要最左面的bitscount位数
    "\n"
    "        srcpos = int(iscoldir == 0u) * ivec2(srcpos.x,gl_GlobalInvocationID.y)\n"
    "                + int(iscoldir == 1u) * ivec2(gl_GlobalInvocationID.x,srcpos.x);\n"
    "        srcpos.x = srcpos.x * 2;\n"
    "\n"
//    "        //读取抽取位置的值 写入缓冲区\n"
    "        complex.x = imageLoad(calcbuf,ivec3(srcpos,calcbufStarti)).x;\n"      //读实部
    "        srcpos.x = srcpos.x + 1;\n"
    "        complex.y = imageLoad(calcbuf,ivec3(srcpos,calcbufStarti)).x;\n"           //读虚部
    "        complex = mulConst * complex;\n"      //总体乘以一个倍率
    "        imageStore(calcbuf,\n"
    "                   ivec3(2u * gl_GlobalInvocationID.x,gl_GlobalInvocationID.y,1-calcbufStarti),\n"
    "                   vec4(complex.x,0,0,0));\n"        //写实部
    "        imageStore(calcbuf,\n"
    "                   ivec3(1u + 2u * gl_GlobalInvocationID.x,gl_GlobalInvocationID.y,1-calcbufStarti),\n"
    "                   vec4(complex.y,0,0,0));\n"       //写虚部
    "        return;\n"
    "    }\n"
    "\n"
    "    if( cyc >= 0 && gl_GlobalInvocationID.x < bufsize.x && gl_GlobalInvocationID.y < bufsize.y ){\n"
    "        highp vec4 complex;\n"
    "        mediump ivec4 srcpos;\n"
    "        srcpos.x = int(iscoldir == 0u) * int(gl_GlobalInvocationID.x)\n"
    "                + int(iscoldir == 1u) * int(gl_GlobalInvocationID.y);\n"
    "        srcpos.y = srcpos.x % (1<<(cyc+1));\n"        //组内序号
    "        srcpos.z = srcpos.y / (1<<cyc);\n"            //分成上下半组，0上半组，1下半组
    "        srcpos.w = srcpos.y % (1<<cyc);\n"                    //旋转WkN序号索引
    "        srcpos.w = srcpos.w * (1<<(bitscount-1-cyc));\n"
//    "        //查找旋转因子WkN\n"
    "        complex.zw = texelFetch(WkN, ivec2(srcpos.w,0), 0).xy;\n"
    "        complex.zw = float(srcpos.z==0)*complex.zw - 1.0f * float(srcpos.z==1)*complex.zw;\n"   //下半组取负数
    "        complex.w = complex.w * alphaImag;\n"        //虚部正负
//    "        //需要乘以旋转因子的索引\n"
    "        srcpos.x = int(srcpos.z==1)*srcpos.x + int(srcpos.z==0)*(srcpos.x + (1<<cyc));\n"
    "        srcpos.xy = int(iscoldir == 0u) * ivec2(srcpos.x,gl_GlobalInvocationID.y)\n"
    "                + int(iscoldir == 1u) * ivec2(gl_GlobalInvocationID.x,srcpos.x);\n"
    "        srcpos.x = srcpos.x * 2;\n"
//    "        //读取蝶形变换左面数据\n"
    "        complex.x = imageLoad(calcbuf,ivec3(srcpos.xy,calcbufStarti)).x;\n"               //读实部
    "        srcpos.x = srcpos.x + 1;\n"
    "        complex.y = imageLoad(calcbuf,ivec3(srcpos.xy,calcbufStarti)).x;\n"                //读虚部
//    "        //乘以旋转因子\n"
    "        complex.zw = vec2(complex.z * complex.x - complex.w * complex.y,\n"
    "                          complex.z * complex.y + complex.w * complex.x\n"
    "                          );\n"                                                    //复数乘法
//    "        //不用乘以旋转因子的索引\n"
    "        srcpos.x = int(iscoldir == 0u) * int(gl_GlobalInvocationID.x)\n"
    "                + int(iscoldir == 1u) * int(gl_GlobalInvocationID.y);\n"
    "        srcpos.x = int(srcpos.z==0)*srcpos.x + int(srcpos.z==1)*(srcpos.x - (1<<cyc));\n"
    "        srcpos.xy = int(iscoldir == 0u) * ivec2(srcpos.x,gl_GlobalInvocationID.y)\n"
    "                + int(iscoldir == 1u) * ivec2(gl_GlobalInvocationID.x,srcpos.x);\n"
    "        srcpos.x = srcpos.x * 2;\n"
//    "        //读取蝶形变换左面数据\n"
    "        complex.x = imageLoad(calcbuf,ivec3(srcpos.xy,calcbufStarti)).x;\n"    //读实部
    "        srcpos.x = srcpos.x + 1;\n"
    "        complex.y = imageLoad(calcbuf,ivec3(srcpos.xy,calcbufStarti)).x;\n"     //读虚部
//    "        //相加得出结果\n"
    "        complex.x = complex.x + complex.z;\n"
    "        complex.y = complex.y + complex.w;\n"
//    "        //写入结果\n"
    "        imageStore(calcbuf,\n"
    "                   ivec3(2u * gl_GlobalInvocationID.x,gl_GlobalInvocationID.y,1-calcbufStarti),\n"
    "                   vec4(complex.x,0,0,0)); \n"  //写实部
    "        imageStore(calcbuf,\n"
    "                   ivec3(1u + 2u * gl_GlobalInvocationID.x,gl_GlobalInvocationID.y,1-calcbufStarti),\n"
    "                   vec4(complex.y,0,0,0)); \n" //写虚部
    "    }\n"
    "\n"
    "}\n"

};

const char* const compute2DTexRowComplexConvShaderStr = {
    "#version 320 es\n"
    "layout (local_size_x = 16, local_size_y = 16) in;\n"
    "precision highp float;\n"
    "\n"
    "layout(location = 0) uniform highp sampler2DArray tex_input1C;\n" //tex_input1C是单精度单通道复数纹理，float[rows][kernelsize.y*2] r32f
    "layout(location = 1) uniform highp sampler2D tex_input2C;\n" //tex_input2C是单精度双通道复数纹理，float[rows][kernelsize.y][2] rg32f
    "layout(location = 2) uniform highp sampler2D tex_kernel;\n"   //卷积核,行数必须与tex_input的列数相等, kernel是单精度双通道得复数纹理, float[kernelsize.y][kernelsize.x][2] rg32f
    "\n"
    "layout(location = 20) uniform mediump ivec2 convsize;\n"   //要进行卷积的方形范围,必须是输入纹理宽度的一半
    "layout(location = 21) uniform mediump ivec2 kernelsize;\n"   //卷积核的尺寸,x为每行每个像素要进行卷积的长度，y为每行每个像素对应不同的卷积核
    "layout(location = 22) uniform lowp int itype;\n"       //输入纹理的类型，0:使用tex_input1C , 1:使用tex_input2C
    "layout(location = 23) uniform lowp int input_index;\n" //用于tex_input1C数组索引
    "\n"
    "layout (binding = 0, r32f) highp uniform image2D resault;\n"  //输出纹理图像
    "\n"
    "void main()\n"
    "{\n"
    "    if(gl_GlobalInvocationID.x < uint(convsize.x) && gl_GlobalInvocationID.y < uint(convsize.y) ){\n"
    "       vec2 sumval = vec2(0);\n"
//    "       sumval.x = texelFetch(tex_input1C,ivec3(gl_GlobalInvocationID.x*2u,gl_GlobalInvocationID.y,input_index),0).x;\n" //取实部
//    "       sumval.y = texelFetch(tex_input1C,ivec3(gl_GlobalInvocationID.x*2u + 1u,gl_GlobalInvocationID.y,input_index),0).x;\n" //取虚部
    "       for(mediump int j = 0; j<kernelsize.x; j++){\n"
    "            vec4 value = vec4(0);\n"
    "            highp int pos = int(gl_GlobalInvocationID.x);\n"
    "            pos = pos - ((kernelsize.x+1)/2 - 1);\n"
    "            pos = pos + j;\n"
//    "            pos = int(pos>=0) * pos; pos = int(pos<convsize.x) * pos + int(pos>=convsize.x) * (convsize.x - 1);\n"   //边缘clamp
    "            pos = int(pos<0)*(2 * convsize.x + pos) + int(pos>=0) * pos;\n"  //小于零转到负频域,大于正频范围本身就会转到负频
    "            if(itype == 0) {\n"
    "               value.x = texelFetch(tex_input1C,ivec3(pos*2,gl_GlobalInvocationID.y,input_index),0).x;\n" //取实部
    "               value.y = texelFetch(tex_input1C,ivec3(pos*2 + 1,gl_GlobalInvocationID.y,input_index),0).x;\n" //取虚部
    "            }else if(itype == 1) {\n"
    "               value.xy = texelFetch(tex_input2C,ivec2(pos,gl_GlobalInvocationID.y ),0).xy;\n"
    "            }\n"
    "            value.zw = texelFetch(tex_kernel,ivec2(j,gl_GlobalInvocationID.x),0).xy;\n"
    "            sumval = sumval + vec2(value.z*value.x - value.w*value.y, value.z*value.y + value.w*value.x);\n"   //复数乘法
    "       }\n"
    "      imageStore(resault,ivec2(gl_GlobalInvocationID.x*2u,gl_GlobalInvocationID.y),vec4(sumval.x));\n"      //写入实部
    "      imageStore(resault,ivec2(gl_GlobalInvocationID.x*2u + 1u,gl_GlobalInvocationID.y),vec4(sumval.y));\n"  //写入虚部
    "    }\n"
    "}\n"
};

const char* const textureTransposeShaderCode = {
    "#version 320 es\n"
    "precision highp float; \n"
    "layout(location = 0) uniform highp sampler2D tex_input;\n"
    "layout(location = 1) uniform highp usampler2D utex_input;\n"
    "layout(location = 2) uniform highp isampler2D itex_input;\n"
    "layout(location = 21) uniform highp ivec2 isize;\n"
    "layout(location = 22) uniform lowp int itype;\n" //0:浮点数纹理,1:无符号整数纹理,2:整数纹理
    "\n"
    "layout(location = 0) out highp vec4 FragColor;\n"
    "layout(location = 1) out highp uvec4 uFragColor;\n"
    "layout(location = 2) out highp ivec4 iFragColor;\n"
    "void main()\n"
    "{\n"
    "    vec4 value;\n"
    "    if(itype == 0) value = texelFetch(tex_input,ivec2(gl_FragCoord.yx),0); \n"    //单精度浮点数
    "    else if(itype == 1) value = vec4(texelFetch(utex_input,ivec2(gl_FragCoord.yx),0)); \n"    //无符号整数
    "    else if(itype == 2) value = vec4(texelFetch(itex_input,ivec2(gl_FragCoord.yx),0)); \n"    //整数
    "    value = float(all(lessThan(ivec2(gl_FragCoord.yx),isize))) * value; \n"     //超出边界直接取零
    "    FragColor = value; \n"
    "    uFragColor = uvec4(value); \n"
    "    iFragColor = ivec4(value); \n"
    "}\n"
};


//const char* const oneDimHistCalcVShaderCode = {
//    "#version 320 es\n"
//    "\n"
//    "layout(location = 0) in float vValue;\n"
//    "\n"
////    "layout(location = 20) uniform lowp int isinteger;\n"   //原始数据是否整数类型， 包括无符号整数
//    "layout(location = 21) uniform highp vec3 range;\n" //x 范围起点，y范围长度, z bins直方柱个数
//    "\n"
//    "void main()\n"
//    "{\n"
//    "    highp float x = vValue - range.x;\n"
//    "    x = x / range.y;\n"
//    "    x = x * (range.z - 1.0f);\n"
////    "    x = float(int(x + 0.5f));\n"  //原始数据为整数要进行舍去小数
//    "    x = x + 0.5f;\n"  //由于顶点着色器 [-1,1] 对应 [0.5,winWidth-0.5],所以起点以0.5计算;这个可能是由于浮点计算精度引起的，不同显卡可能会不一样
////    "    if( isinteger != 0) x = float(int(x + 0.5f));\n"  //原始数据为整数要进行舍去小数
////    "    x = float(int(x + 0.5f));\n"  //原始数据为整数要进行舍去小数
//    "    x = x / range.z;\n"
//    "    x = x * 2.0f - 1.0f;\n"    //转为 -1~1
//    "    gl_PointSize = 0.5f;\n"    //设置点的大小为0.5个像素
//    "    gl_Position = vec4(x,0,0,1);\n"
//    "}\n"
//};

//const char* const oneDimHistCalcFShaderCode = {
//    "#version 320 es\n"
//    "precision highp float; \n"
//    "\n"
//    "out highp float FragColor;\n"
//    "void main()\n"
//    "{\n"
//    "    FragColor = 1.0f; \n" //gl_PointCoord gl_FragCoord
//    "}\n"
//};


const char* const oneDimHistCalcFShaderCode = {
    "#version 320 es\n"
//    "#extension GL_OES_shader_image_atomic : enable\n"   //3.1es 没有图像原子操作，要加上这个扩展
    "precision highp float; \n"
    "layout(location = 0) uniform highp sampler2D tex_input;\n"
    "layout(location = 1) uniform highp usampler2D utex_input;\n"
    "layout(location = 2) uniform highp isampler2D itex_input;\n"
    "\n"
    "layout(location = 21) uniform highp vec3 range;\n" //x 范围起点，y范围长度, z bins直方柱个数
    "layout(location = 22) uniform lowp int itype;\n" //0:浮点数纹理,1:无符号整数纹理,2:整数纹理
    "\n"
    "layout (binding = 0, r32ui) highp uniform coherent uimage2D hist;\n"
    "\n"
    "void main()\n"
    "{\n"
    "    highp float x;\n"  //如果 x=1.0f的话，下面不进行四舍五入的话,会计入到bins =0 的位置
    "    if(itype == 0) x = texelFetch(tex_input,ivec2(gl_FragCoord.xy),0).x; \n"    //单精度浮点数
    "    else if(itype == 1) x = float(texelFetch(utex_input,ivec2(gl_FragCoord.xy),0).x); \n"    //无符号整数
    "    else if(itype == 2) x = float(texelFetch(itex_input,ivec2(gl_FragCoord.xy),0).x); \n"    //整数
    "    x = x - range.x;\n"
    "    x = x / range.y;\n"
    "    if(x<0.0f || x>range.y ){discard;return;};\n"
    "    x = x * (range.z - 1.0f);\n"
    "    x = x + 0.5f;\n"   //范围变成 0.5 ~ (range.z - 0.5f), 使其四舍五入
//    "    x = float(int(x));\n"
    "    imageAtomicAdd(hist, ivec2(x,0), 1u);\n"
    "    memoryBarrierImage();\n"       //等待图像写入操作完成
    "    discard;\n"
    "}\n"
};

const char* const tex2DConv2DFShaderCode = {
    "#version 320 es\n"
    "precision highp float;\n"
    "\n"
    "layout(location = 0) uniform highp sampler2D tex_input;\n"
    "layout(location = 1) uniform highp usampler2D utex_input;\n"
    "layout(location = 2) uniform highp isampler2D itex_input;\n"
    "\n"
    "layout(location = 5) uniform highp sampler2D tex_kernel;\n"    //纹理卷积核
    "\n"
    "layout(location = 20) uniform lowp ivec2 kernelshape;\n"   //卷积核的尺寸
    "layout(location = 21) uniform lowp int paddingmode;\n"   //越界时的填充方式,0:填充零，1:填充边界 , 2:镜像重复填充
    "layout(location = 22) uniform lowp ivec2 iotype;"           //type.x输入的纹理数据类型 type.y输出的纹理数据类型\n
    "layout(location = 23) uniform mediump ivec2 texsize;\n"     //输入纹理的宽高
    "\n"
    "layout(location = 0) out highp vec4 FragColor;\n"
    "layout(location = 1) out highp uvec4 uFragColor;\n"
    "layout(location = 2) out highp ivec4 iFragColor;\n"
    "\n"
    "void main()\n"
    "{\n"
    "    FragColor = vec4(0);\n"
    "    for(lowp int i=0;i<kernelshape.y;i++){\n"
    "        for(lowp int j=0;j<kernelshape.x;j++){\n"
    "            vec4 value;\n"
    "            highp ivec2 pos = ivec2(gl_FragCoord.xy);\n"
    "            pos.x = pos.x - ((kernelshape.x+1)/2 - 1);\n"
    "            pos.y = pos.y - ((kernelshape.y+1)/2 - 1);\n"
    "            pos.x = pos.x + j;\n"
    "            pos.y = pos.y + i;\n"
//    "            pos = pos * 2 - texsize/2;\n"      //测试填充用
    "            if(paddingmode==1){\n"    //填充边界值
    "                pos.x = int(pos.x >= 0) * pos.x; pos.y = int(pos.y >= 0) * pos.y;\n"
    "                pos.x = int(pos.x >= texsize.x)*(texsize.x - 1)+int(pos.x < texsize.x)*pos.x;\n"
    "                pos.y = int(pos.y >= texsize.y)*(texsize.y - 1)+int(pos.y < texsize.y)*pos.y;\n"
    "            }else if(paddingmode==2){\n"  //填充镜像重复值
    "                pos.x = int(pos.x < 0) * (-pos.x) + int(pos.x >= 0) * (pos.x);\n"
    "                pos.y = int(pos.y < 0) * (-pos.y) + int(pos.y >= 0) * (pos.y);\n"
    "                pos.x = pos.x % (2 * texsize.x - 2);\n"
    "                pos.x = int(pos.x >= texsize.x) * (2 * texsize.x - 2 - pos.x)+int(pos.x < texsize.x)*pos.x;\n"
    "                pos.y = pos.y % (2 * texsize.y - 2);\n"
    "                pos.y = int(pos.y >= texsize.y) * (2*texsize.y-2 - pos.y) + int(pos.y < texsize.y)*pos.y;\n"
    "            }\n"
    "            if(iotype.x == 0) value = texelFetch(tex_input,pos,0);\n"
    "            else if(iotype.x == 1) value = vec4(texelFetch(utex_input,pos,0));\n"
    "            else if(iotype.x == 2) value = vec4(texelFetch(itex_input,pos,0));\n"
//    "            if(paddingmode==0){\n"    //超出边界填充零 不需要做处理了，因为texelFetch本来越界就是取0
//    "                value = value * float(all(greaterThanEqual(pos,ivec2(0)) && lessThan(pos,texsize)));\n"
//    "            }\n"
    "            value = value * texelFetch(tex_kernel,ivec2(j,i),0);\n"
    "            FragColor = FragColor + value;\n"
    "        }\n"
    "    }\n"
    "    uFragColor = uvec4(FragColor);\n"
    "    iFragColor = ivec4(FragColor);\n"
    "}\n"
};

const char* const tex2DConv2DSobelFShaderCode = {
    "#version 320 es\n"
    "precision highp float;\n"
    "\n"
    "layout(location = 0) uniform highp sampler2D tex_input;\n"
    "layout(location = 1) uniform highp usampler2D utex_input;\n"
    "layout(location = 2) uniform highp isampler2D itex_input;\n"
    "\n"
    "layout(location = 20) uniform highp mat3 kernelsobel;\n"   //sobel卷积核
    "layout(location = 21) uniform lowp int paddingmode;\n"   //越界时的填充方式,0:填充零，1:填充边界 , 2:镜像重复填充
    "layout(location = 22) uniform lowp ivec2 iotype;"           //type.x输入的纹理数据类型 type.y输出的纹理数据类型\n
    "layout(location = 23) uniform mediump ivec2 texsize;\n"     //输入纹理的宽高
    "\n"
    "layout(location = 0) out highp vec4 FragColor;\n"
    "layout(location = 1) out highp uvec4 uFragColor;\n"
    "layout(location = 2) out highp ivec4 iFragColor;\n"
    "\n"
    "void main()\n"
    "{\n"
    "    FragColor = vec4(0);\n"
    "    for(lowp int i=0;i<3;i++){\n"
    "        for(lowp int j=0;j<3;j++){\n"
    "            vec4 value;\n"
    "            highp ivec2 pos = ivec2(gl_FragCoord.xy);\n"
    "            pos.x = pos.x - 1;\n"
    "            pos.y = pos.y - 1;\n"
    "            pos.x = pos.x + j;\n"
    "            pos.y = pos.y + i;\n"
//    "            pos = pos * 2 - texsize/2;\n"      //测试填充用
    "            if(paddingmode==1){\n"    //填充边界值
    "                pos.x = int(pos.x >= 0) * pos.x; pos.y = int(pos.y >= 0) * pos.y;\n"
    "                pos.x = int(pos.x >= texsize.x)*(texsize.x - 1)+int(pos.x < texsize.x)*pos.x;\n"
    "                pos.y = int(pos.y >= texsize.y)*(texsize.y - 1)+int(pos.y < texsize.y)*pos.y;\n"
    "            }else if(paddingmode==2){\n"  //填充镜像重复值
    "                pos.x = int(pos.x < 0) * (-pos.x) + int(pos.x >= 0) * (pos.x);\n"
    "                pos.y = int(pos.y < 0) * (-pos.y) + int(pos.y >= 0) * (pos.y);\n"
    "                pos.x = pos.x % (2 * texsize.x - 2);\n"
    "                pos.x = int(pos.x >= texsize.x) * (2 * texsize.x - 2 - pos.x)+int(pos.x < texsize.x)*pos.x;\n"
    "                pos.y = pos.y % (2 * texsize.y - 2);\n"
    "                pos.y = int(pos.y >= texsize.y) * (2*texsize.y-2 - pos.y) + int(pos.y < texsize.y)*pos.y;\n"
    "            }\n"
    "            if(iotype.x == 0) value = texelFetch(tex_input,pos,0);\n"
    "            else if(iotype.x == 1) value = vec4(texelFetch(utex_input,pos,0));\n"
    "            else if(iotype.x == 2) value = vec4(texelFetch(itex_input,pos,0));\n"
//    "            if(paddingmode==0){\n"    //超出边界填充零 不需要做处理了，因为texelFetch本来越界就是取0
//    "                value = value * float(all(greaterThanEqual(pos,ivec2(0)) && lessThan(pos,texsize)));\n"
//    "            }\n"
    "            value = value * kernelsobel[j][i];\n" //列优先，第j列，第i行
    "            FragColor = FragColor + value;\n"
    "        }\n"
    "    }\n"
    "    uFragColor = uvec4(FragColor);\n"
    "    iFragColor = ivec4(FragColor);\n"
    "}\n"
};


const char* const tex2DConv2DSobelCShaderCode = {
    "#version 320 es\n"
    "precision highp float;\n"
    "\n"
    "layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in;\n"       //这个可以根据显卡性能来更改
    "\n"
    "layout(location = 0) uniform highp sampler2D tex_input;\n"
    "layout(location = 1) uniform highp usampler2D utex_input;\n"
    "layout(location = 2) uniform highp isampler2D itex_input;\n"
    "\n"
    "layout(location = 21) uniform lowp int paddingmode;\n"   //越界时的填充方式,0:填充零，1:填充边界 , 2:镜像重复填充
    "layout(location = 22) uniform lowp ivec2 iotype;"           //type.x输入的纹理数据类型 type.y输出的纹理数据类型\n
    "layout(location = 23) uniform mediump ivec2 texsize;\n"     //输入纹理的宽高
    "layout(location = 24) uniform highp mat3 kernelsobelx;\n"   //sobel卷积核 x方向
    "layout(location = 25) uniform highp mat3 kernelsobely;\n"   //sobel卷积核 y方向
    "\n"
    "layout (binding = 0, r32f) highp uniform image2D resultx;\n"    //x方向卷积结果
    "layout (binding = 1, r32f) highp uniform image2D resulty;\n"    //x方向卷积结果
    "layout (binding = 2, r32f) highp uniform image2D result;\n"    //两个方向根方和结果
    "\n"
    "void main()\n"
    "{\n"
    "    if(gl_GlobalInvocationID.x < uint(texsize.x) && gl_GlobalInvocationID.y < uint(texsize.y) ){"
    "    highp vec2 sumtemp = vec2(0);\n"
    "       for(lowp int i=0;i<3;i++){\n"
    "           for(lowp int j=0;j<3;j++){\n"
    "               highp float value = 0.0f;\n"
    "               highp ivec2 pos = ivec2(gl_GlobalInvocationID.xy);\n"
    "               pos.x = pos.x - 1;\n"
    "               pos.y = pos.y - 1;\n"
    "               pos.x = pos.x + j;\n"
    "               pos.y = pos.y + i;\n"
//    "               pos = pos * 2 - texsize/2;\n"      //测试填充用
    "               if(paddingmode==1){\n"    //填充边界值
    "                   pos.x = int(pos.x >= 0) * pos.x; pos.y = int(pos.y >= 0) * pos.y;\n"
    "                   pos.x = int(pos.x >= texsize.x)*(texsize.x - 1)+int(pos.x < texsize.x)*pos.x;\n"
    "                   pos.y = int(pos.y >= texsize.y)*(texsize.y - 1)+int(pos.y < texsize.y)*pos.y;\n"
    "               }else if(paddingmode==2){\n"  //填充镜像重复值
    "                   pos.x = int(pos.x < 0) * (-pos.x) + int(pos.x >= 0) * (pos.x);\n"
    "                   pos.y = int(pos.y < 0) * (-pos.y) + int(pos.y >= 0) * (pos.y);\n"
    "                   pos.x = pos.x % (2 * texsize.x - 2);\n"
    "                   pos.x = int(pos.x >= texsize.x) * (2 * texsize.x - 2 - pos.x)+int(pos.x < texsize.x)*pos.x;\n"
    "                   pos.y = pos.y % (2 * texsize.y - 2);\n"
    "                   pos.y = int(pos.y >= texsize.y) * (2*texsize.y-2 - pos.y) + int(pos.y < texsize.y)*pos.y;\n"
    "               }\n"
    "               if(iotype.x == 0) value = texelFetch(tex_input,pos,0).x;\n"
    "               else if(iotype.x == 1) value = vec4(texelFetch(utex_input,pos,0)).x;\n"
    "               else if(iotype.x == 2) value = vec4(texelFetch(itex_input,pos,0)).x;\n"
//    "               if(paddingmode==0){\n"    //超出边界填充零 不需要做处理了，因为texelFetch本来越界就是取0
//    "                   value = value * float(all(greaterThanEqual(pos,ivec2(0)) && lessThan(pos,texsize)));\n"
//    "               }\n"
    "               sumtemp.x = sumtemp.x + value * kernelsobelx[j][i];\n" //列优先，第j列，第i行
    "               sumtemp.y = sumtemp.y + value * kernelsobely[j][i];\n"
    "           }\n"
    "       }\n"
    "       imageStore(resultx,ivec2( gl_GlobalInvocationID.x,gl_GlobalInvocationID.y),vec4(sumtemp.x));\n"        //保存x方向梯度
    "       imageStore(resulty,ivec2( gl_GlobalInvocationID.x,gl_GlobalInvocationID.y),vec4(sumtemp.y));\n"        //保存y方向梯度
    "       sumtemp.x = sumtemp.x * sumtemp.x + sumtemp.y * sumtemp.y;\n"
    "       sumtemp.x = sqrt(sumtemp.x);\n"
    "       imageStore(result,ivec2( gl_GlobalInvocationID.x,gl_GlobalInvocationID.y),vec4(sumtemp.x));\n"        //保存两个方向平方根
    "    }\n"
    "}\n"
};

const char* const tex2DCannyNonMaxSupCShaderCode = {
    "#version 320 es\n"
    "precision highp float;\n"
    "\n"
    "layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in;\n"       //这个可以根据显卡性能来更改
    "\n"
    "layout(location = 23) uniform mediump ivec2 imgsize;\n"     //处理梯度纹理图像的宽高
    "\n"
    "layout (binding = 0, r32f) highp uniform image2D gradientx;\n"    //x方向梯度值
    "layout (binding = 1, r32f) highp uniform image2D gradienty;\n"    //y方向梯度值
    "layout (binding = 2, r32f) highp uniform image2D gradient;\n"    //两个方向梯度根方和
    "layout (binding = 3, r32f) highp uniform image2D result;\n"        //非极大值抑制结果存放
    "\n"
    "void main()\n"
    "{\n"
    "    if(gl_GlobalInvocationID.x < uint(imgsize.x) && gl_GlobalInvocationID.y < uint(imgsize.y) ){"
    "       highp vec3 value;\n"
    "       mediump ivec4 pos = ivec4( gl_GlobalInvocationID.x,gl_GlobalInvocationID.y,0,0);\n"
    "       value.x = imageLoad(gradientx,pos.xy).x;\n"
    "       value.y = imageLoad(gradienty,pos.xy).x;\n"
    "       pos.z = int(value.x * value.y >= 0.0) - int(value.x * value.y < 0.0);\n"    //x y 方向的梯度正负不一样时要取-1
    "       pos.w = pos.z;\n"
    "       value.x = abs(value.x);\n"     //其余使用绝对值计算权重，和方向近似
    "       value.y = abs(value.y);\n"
    "       pos.z = int(value.x <= value.y) * pos.z;\n"   //梯度方向近似的点,y方向梯度绝对值较大由Y轴方向取近似点，否则由X轴方向取近似点
    "       pos.w = int(value.y <= value.x) * pos.w;\n"
    "       value.y = value.x / value.y;\n"     //求取插值权重
    "       if(isnan(value.y)) value.y = 1.0f;\n" //非浮点权重修正为1
//    "       if(isinf(value.y)) value.y = 0.0f;\n" //无穷大权重修正为0
    "       if(value.y > 1.0f) value.y = 1.0f / value.y;\n" //大于1的值要倒数
    "       value.x = imageLoad(gradient,pos.xy).x;\n"     //读取中心梯度
    //获取插值1
    "       pos.xy = ivec2(pos.z == 0,pos.w == 0) + pos.zw;\n"
    "       pos.xy = ivec2(gl_GlobalInvocationID.xy) + pos.xy;\n"
    "       value.z = value.y*imageLoad(gradient,pos.xy).x;\n"  //不在正交轴上的位置
    "       pos.xy = ivec2(pos.z == 0,pos.w == 0);\n"
    "       pos.xy = ivec2(gl_GlobalInvocationID.xy) + pos.xy;\n"
    "       value.z = value.z + (1.0f - value.y)*imageLoad(gradient,pos.xy).x;\n" //在正交轴上的位置
    "       value.x = float( value.z <= value.x ) * value.x;\n" //不是极值清零
    //获取插值2
    "       pos.xy = ivec2(pos.z == 0,pos.w == 0) + pos.zw;\n"
    "       pos.xy = ivec2(gl_GlobalInvocationID.xy) - pos.xy;\n"
    "       value.z = value.y*imageLoad(gradient,pos.xy).x;\n"  //不在正交轴上的位置
    "       pos.xy = ivec2(pos.z == 0,pos.w == 0);\n"
    "       pos.xy = ivec2(gl_GlobalInvocationID.xy) - pos.xy;\n"
    "       value.z = value.z + (1.0f - value.y)*imageLoad(gradient,pos.xy).x;\n" //在正交轴上的位置
    "       value.x = float( value.z <= value.x ) * value.x;\n" //不是极值清零
    //保存非极大值过滤后的结果
    "       imageStore(result,ivec2(gl_GlobalInvocationID.xy),vec4(value.x));\n"
    "    }\n"
    "}\n"
};

const char* const tex2DEdgeThreshCShaderCode = {
    "#version 320 es\n"
    "precision highp float;\n"
    "\n"
    "layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in;\n"       //这个可以根据显卡性能来更改
    "\n"
    "layout(location = 20) uniform highp vec2 thresh;\n"     //阈值上下限, x下限 , y 上限
    "layout(location = 23) uniform mediump ivec2 imgsize;\n"     //处理边缘纹理图像的宽高
    "\n"
    "layout (binding = 2, r32f) highp uniform image2D result;\n"    //存放阈值结果
    "layout (binding = 3, r32f) highp uniform image2D edge;\n"        //边缘纹理图像数据
    "\n"
    "void main()\n"
    "{\n"
    "    if(gl_GlobalInvocationID.x < uint(imgsize.x) && gl_GlobalInvocationID.y < uint(imgsize.y) ){"
    "       highp float value = imageLoad(edge, ivec2(gl_GlobalInvocationID.xy)).x;\n"
    "       bool iskeep = false;\n"
    "       for(lowp int i = -1; i<2; i++){ \n"
    "           for(lowp int j = -1; j<2; j++){ \n"
    "               if(j == 0 && i == 0) continue;\n"
    "               iskeep = iskeep || (imageLoad(edge, ivec2(gl_GlobalInvocationID.xy)+ivec2(i,j)).x > thresh.y);\n"
    "           }\n"
    "       }\n"
    "       iskeep = iskeep && ( value > thresh.x);\n"
    "       iskeep = iskeep || ( value > thresh.y);\n"
    "       value = float(iskeep && (thresh.x == thresh.y)) * value + float(iskeep && (thresh.x != thresh.y)) * 255.0f;\n"
    "       imageStore(result,ivec2(gl_GlobalInvocationID.xy),vec4(value));\n"
    "    }\n"
    "}\n"
};
